#pragma once
#include <functional>
#include <thread>
#include <atomic>
#include <chrono>
#include <mutex>
#include <condition_variable>

class Timer {
public:
    /**
     * @brief Constructs a new Timer object that will execute a given function at a fixed interval.
     *
     * @param interval_ms The time interval in milliseconds between each execution of the task function.
     * @param taskFunc A function to be executed repeatedly at the specified interval.
     */
    Timer(unsigned int interval_ms, std::function<void(uint64_t)> taskFunc);

    /**
     * @brief Destructor for the Timer object. This will stop the timer and wait for any currently running tasks to complete before destroying the Timer instance.
     */
    ~Timer();

    /**
     * @brief Start the timer. The timer will begin executing the provided function at the specified interval.
     *
     * @note If the timer is already started, this method has no effect.
     */
    void start();
    
    /**
     * @brief Stop the timer. This will prevent any further executions of the task function.
     *
     * @note This method does not wait for any currently running tasks to complete before returning.
     */
    void stop();

    /**
     * @brief Wait for the timer to finish executing all remaining tasks before continuing.
     *
     * @details This method will block the calling thread until the Timer object has stopped and all outstanding tasks have completed execution.
     */
    void wait();

    /**
     * @brief Returns the current time in microseconds since an unspecified point in the past (typically, the system start).
     *
     * @return uint64_t The current time in microseconds.
     */
    static uint64_t getCurrentTimeMicroseconds();
    
private:
    /**
     * @brief The main loop that executes the task function at the specified interval.
     *
     * @details This method will continue executing as long as the timer is running and the task function has not been cancelled. It will wait for the next scheduled execution time before calling the task function again.
     */
    void run();

private:
    unsigned int interval; /*!< The time interval between each execution of the task function in microseconds. */
    std::function<void(uint64_t)> task; /*!< The function to be executed at each interval. It receives the current time in microseconds as an argument */

    std::atomic<bool> running; /*!< A flag indicating whether the timer is currently running. */
    std::thread worker; /*!< The thread that will execute the task function at each interval. */

    std::mutex mtx; /*!< A mutex to protect access to the shared resources of the Timer class. */
    std::condition_variable cv; /*!< A condition variable used to signal when the next execution time has arrived. */
    bool is_ready = false; /*!< A flag indicating whether the timer is ready to execute the task function. */
};
